/******************************************************************
 *  MRRM's instruction decode unit                                *
 *                                                                *
 *  This file is part of the MRRM project                         *
 *  <http://mrrm.googlecode.com/>                                 *
 *                                                                *
 *  Author(s):                                                    *
 *    -  Yuan Pengfei <coolypf@opencores.org>                     *
 *                                                                *
 ******************************************************************
 *                                                                *
 *  Copyright (C) 2010 AUTHORS                                    *
 *                                                                *
 *  This source file may be used and distributed without          *
 *  restriction provided that this copyright statement is not     *
 *  removed from the file and that any derivative work contains   *
 *  the original copyright notice and the associated disclaimer.  *
 *                                                                *
 *  MRRM is free software: you can redistribute it and/or modify  *
 *  it under the terms of the GNU General Public License as       *
 *  published by the Free Software Foundation, either version 3   *
 *  of the License, or (at your option) any later version.        *
 *                                                                *
 *  MRRM is distributed in the hope that it will be useful, but   *
 *  WITHOUT ANY WARRANTY; without even the implied warranty of    *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  *
 *  GNU General Public License for more details.                  *
 *                                                                *
 *  You should have received a copy of the GNU General Public     *
 *  License along with MRRM. If not, see                          *
 *  <http://www.gnu.org/licenses/>.                               *
 *                                                                *
 ******************************************************************/

`include "global.v"

module mrrm_id(
	// ID interface
	D_insn, D_valp, d_vala, d_valb, d_valc, d_vale,
	d_itype, d_isubtype, d_ifun, d_snl, d_dstx, d_dsty, d_wrx, d_wry,
	// RF interface
	addra, addrb, addrc, dataa, datab, datac,
	// EXE interface
	E_dstx, E_dsty, E_wrx, E_wry, e_valx, e_valy,
	// MEM interface
	M_itype, M_snl, M_dstx, M_dsty, M_wrx, M_wry, m_valm, M_valx, M_valy,
	// WB interface
	W_itype, W_snl, W_dstx, W_dsty, W_wrx, W_wry, W_valm, W_valx, W_valy,
	// Pipeline control interface
	d_srca, d_srcb, d_srcc
	);

parameter rw = `REGFILE_ADDR_WIDTH;
parameter mw = `MEMORY_ADDR_WIDTH;
parameter iw = `INSTRUCTION_WIDTH;
parameter ow = `OPERAND_WIDTH;

// Interfaces
// ID
input [iw-1:0] D_insn;
input [mw-1:0] D_valp;
output [ow-1:0] d_vala;
output [ow-1:0] d_valb;
output [ow-1:0] d_valc;
output [ow-1:0] d_vale;
output [2:0] d_itype;
output [1:0] d_isubtype;
output [3:0] d_ifun;
output d_snl;
output [rw-1:0] d_dstx;
output [rw-1:0] d_dsty;
output d_wrx;
output d_wry;

// RF
output [rw-1:0] addra;
output [rw-1:0] addrb;
output [rw-1:0] addrc;
input [ow-1:0] dataa;
input [ow-1:0] datab;
input [ow-1:0] datac;

// EXE
input [rw-1:0] E_dstx;
input [rw-1:0] E_dsty;
input E_wrx;
input E_wry;
input [ow-1:0] e_valx;
input [ow-1:0] e_valy;

// MEM
input [2:1] M_itype;				// 2 bits are enough
input M_snl;
input [rw-1:0] M_dstx;
input [rw-1:0] M_dsty;
input M_wrx;
input M_wry;
input [ow-1:0] m_valm;
input [ow-1:0] M_valx;
input [ow-1:0] M_valy;

// WB
input [2:1] W_itype;				// 2 bits are enough
input W_snl;
input [rw-1:0] W_dstx;
input [rw-1:0] W_dsty;
input W_wrx;
input W_wry;
input [ow-1:0] W_valm;
input [ow-1:0] W_valx;
input [ow-1:0] W_valy;

// Pipeline control
output [rw-1:0] d_srca;
output [rw-1:0] d_srcb;
output [rw-1:0] d_srcc;

// Internal wires
wire [2:0] itype;
wire [1:0] isubtype;
wire [3:0] ifun;
wire snl;
wire [rw-1:0] rs1;
wire [rw-1:0] rs2;
wire [rw-1:0] rd1;
wire [rw-1:0] rd2;
wire [4:0] imm5;
wire [8:0] imm9;
wire [13:0] imm14;

// Decode
assign itype = D_insn[31:29];
assign isubtype = {D_insn[8], D_insn[5]};
assign ifun = D_insn[28:25];
assign snl = D_insn[`SNL_BIT];
assign rs1 = D_insn[23:19];
assign rs2 = D_insn[4:0];
assign rd1 = D_insn[18:14];
assign rd2 = D_insn[13:9];
assign imm5 = D_insn[13:9];
assign imm9 = D_insn[8:0];
assign imm14 = D_insn[13:0];

// Pass decode result
assign d_itype = itype;
assign d_isubtype = isubtype;
assign d_ifun = ifun;
assign d_snl = snl;
assign d_dstx = (snl == 1'b1 && (itype == `I_BXX ||
	{itype, isubtype, ifun} == {`I_REG, `S_TWO, `F_JUMP}))
	? `REG_LR : rd1;
assign d_dsty = rd2;
assign d_wrx = ({itype[2:1], ifun[3:2]} == 4'b0010		// compare
	|| {itype, snl} == {`I_BXX, 1'b0}						// branch, no link
	|| {itype[2:1], snl} == 3'b010							// store
	|| {itype, isubtype, ifun, snl} == {`I_REG, `S_TWO, `F_JUMP, 1'b0}		// jump, no link
	|| itype == `I_NOP
	|| itype == `I_HLT )
	? 1'b0 : 1'b1;
assign d_wry = ({itype, isubtype, ifun} == {`I_REG, `S_TWO, `F_MULSL})
	? 1'b1 : 1'b0;

// RF read port
assign addra = rs1;
assign addrb = rs2;
assign addrc = rd1;

// Value A
assign d_vala = (rs1 == `REG_PC || snl == 1'b1 && (itype == `I_BXX
		|| {itype, isubtype, ifun} == {`I_REG, `S_TWO, `F_JUMP})) ? D_valp
	: ({E_wrx, E_dstx} == {1'b1, rs1}) ? e_valx
	: ({E_wry, E_dsty} == {1'b1, rs1}) ? e_valy
	: ({M_itype[2:1], M_snl, M_dstx} == {3'b011, rs1}) ? m_valm
	: ({M_wrx, M_dstx} == {1'b1, rs1}) ? M_valx
	: ({M_wry, M_dsty} == {1'b1, rs1}) ? M_valy
	: ({W_itype[2:1], W_snl, W_dstx} == {3'b011, rs1}) ? W_valm
	: ({W_wrx, W_dstx} == {1'b1, rs1}) ? W_valx
	: ({W_wry, W_dsty} == {1'b1, rs1}) ? W_valy
	: dataa;
	
// Value B
assign d_valb = (itype == `I_IMM) ? {23'b0, imm9}
	: (itype == `I_LSI) ? {18'b0, imm14}
	: (rs2 == `REG_PC) ? D_valp
	: ({E_wrx, E_dstx} == {1'b1, rs2}) ? e_valx
	: ({E_wry, E_dsty} == {1'b1, rs2}) ? e_valy
	: ({M_itype[2:1], M_snl, M_dstx} == {3'b011, rs2}) ? m_valm
	: ({M_wrx, M_dstx} == {1'b1, rs2}) ? M_valx
	: ({M_wry, M_dsty} == {1'b1, rs2}) ? M_valy
	: ({W_itype[2:1], W_snl, W_dstx} == {3'b011, rs2}) ? W_valm
	: ({W_wrx, W_dstx} == {1'b1, rs2}) ? W_valx
	: ({W_wry, W_dsty} == {1'b1, rs2}) ? W_valy
	: datab;

// Value C
assign d_valc = ({itype[2], itype[0], isubtype} == 4'b0) ? {27'b0, imm5} : 32'b0;

// Value E
assign d_vale = (rd1 == `REG_PC) ? D_valp
	: ({E_wrx, E_dstx} == {1'b1, rd1}) ? e_valx
	: ({E_wry, E_dsty} == {1'b1, rd1}) ? e_valy
	: ({M_itype[2:1], M_snl, M_dstx} == {3'b011, rd1}) ? m_valm
	: ({M_wrx, M_dstx} == {1'b1, rd1}) ? M_valx
	: ({M_wry, M_dsty} == {1'b1, rd1}) ? M_valy
	: ({W_itype[2:1], W_snl, W_dstx} == {3'b011, rd1}) ? W_valm
	: ({W_wrx, W_dstx} == {1'b1, rd1}) ? W_valx
	: ({W_wry, W_dsty} == {1'b1, rd1}) ? W_valy
	: datac;

// Pipeline control
assign d_srca = (itype[2] == 1'b0) ? rs1 : 5'b11111;
assign d_srcb = ({itype[2], itype[0]} == 2'b00) ? rs2 : 5'b11111;
assign d_srcc = ({itype[2:1], snl} == 3'b010) ? rd1 : 5'b11111;

endmodule
